/* Copyright (c) 2016-2020 Enfry Ltd. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of Enfry. 
 * You shall not disclose such Confidential Information
 * and shall use it only in accordance with the terms of the agreements
 * you entered into with Enfry.
 */
package com.enfry.common.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import com.enfry.common.util.String.Strings;
import com.enfry.common.util.constants.CodeConstants;
import com.enfry.common.util.control.Filter;
import com.enfry.common.util.control.FilterEndsWith;
import com.enfry.common.util.system.Systems;
import com.enfry.common.util.validate.Validates;

/**
 * 
 * 文件操作工具类
 * 
 * @Title com.enfry.util.Files
 * @author Penghu
 * @date 2018年1月4日
 */
public class Files implements CodeConstants {
	/**
	 * 把Windows的Path替换成linux的path，即把\替换成/
	 * 
	 * @param path Windows的Path
	 * @return Linux的Path
	 */
	public static String toLinuxPath(String path) {
		return Replaces.replaceAllEscape(path, "\\", "/");
	}

	/**
	 * 判断文件是否存在(包括目录和文件)
	 * 
	 * @param path 文件或目录
	 * @return true/false 存在则返回true
	 */
	public static boolean exists(File path) {
		if (path == null)
			return false;

		try {
			return path.exists();
		} catch (Throwable e) {// 有安全管理访问的访问异常，返回false;
			return false;
		}
	}

	/**
	 * 判断文件是否存在(包括目录和文件)
	 * 
	 * @param path 文件或目录完整路径
	 * @return true/false 存在则返回true
	 */
	public static boolean exists(String path) {
		if (Validates.isEmpty(path))
			return false;

		return exists(new File(path));
	}

	/**
	 * 判断文件是否存在(包括目录和文件)，将在V1.2.3中删除，请使用exists方法
	 * 
	 * @param path 文件或目录
	 * @return true/false 存在则返回true
	 */
	@Deprecated
	public static boolean isExists(File path) {
		return exists(path);
	}

	/**
	 * 判断文件是否存在(包括目录和文件)
	 * 
	 * @param path 文件或目录完整路径
	 * @return true/false 存在则返回true
	 */
	@Deprecated
	public static boolean isExists(String path) {
		return exists(path);
	}

	/**
	 * 判断文件是否存在
	 * 
	 * @param path 文件完整路径
	 * @return true/false 存在则返回true
	 */
	public static boolean isFile(String path) {
		if (Validates.isEmpty(path))
			return false;

		File file = new File(path);
		return isFile(file);
	}

	/**
	 * 判断文件是否存在
	 * 
	 * @param file 文件
	 * @return true/false 存在则返回true
	 */
	public static boolean isFile(File file) {
		if (file == null)
			return false;

		if (!file.exists())
			return false;

		return file.isFile();
	}

	/**
	 * 判断路径是否为目录
	 * 
	 * @param path 要判断的目录路径
	 * @return true/false 如果是目录，返回true
	 */
	public static boolean isDirectory(String path) {
		if (Validates.isEmpty(path))
			return false;

		File dirFile = new File(path);
		return isDirectory(dirFile);
	}

	/**
	 * 判断路径是否为目录
	 * 
	 * @param dir 目录对象
	 * @return true/false 如果是目录，返回true
	 */
	public static boolean isDirectory(File dir) {
		if (dir == null)
			return false;

		if (!dir.exists())
			return false;

		return dir.isDirectory();
	}

	/**
	 * 递归创建文件目录
	 * 
	 * @param fileDir 要求创建的文件目录
	 * @return true/false
	 */
	public static boolean mkDirectory(String fileDir) {
		File dir = new File(fileDir);
		if (dir.exists())
			return true;

		if (!dir.getParentFile().exists())
			mkDirectory(dir.getParent());

		return dir.mkdir();
	}

	/**
	 * 拷贝目录 成功返回true,不是目录或dest路径书写错误返回false
	 * 
	 * @param src 源目录
	 * @param dest 目标目录
	 * @return 成功返回true,不是目录或dest路径书写错误返回false
	 */
	public static boolean copyDirectory(File src, String dest) throws Exception {
		if ((src == null) || !src.isDirectory())
			return false;

		File destRoot = new File(dest);
		if (!destRoot.exists())
			destRoot.mkdir();

		File[] entries = src.listFiles();
		int len = entries.length;
		for (int i = 0; i < len; i++) {
			File entry = entries[i];
			String target = dest + Systems.getFileSeparator() + entry.getName();
			if (entry.isDirectory()) {
				copyDirectory(entry, target); // 递归
			} else {
				File toFile = new File(target);
				copyFile(entry, toFile);
			}
		}

		return true;
	}

	/**
	 * 创建文件，指定文件
	 * 
	 * @param filePath 文件路径
	 * @return =true表示创建成功，=false表示创建失败
	 */
	public static boolean newFile(String filePath) {
		return newFile(new File(filePath));
	}

	/**
	 * 创建文件，指定文件
	 * 
	 * @param file 文件对象
	 * @return =true表示创建成功，=false表示创建失败
	 */
	public static boolean newFile(File file) {
		try {
			if (file.exists())
				return true;

			String fileDir = file.getParent();
			Files.mkDirectory(fileDir);

			file.createNewFile();
			return true;
		} catch (Throwable e) {
			return false;
		}
	}

	/**
	 * 文件拷贝，逐个字节拷贝到新的文件中件
	 * 
	 * @param fromFile 源文件对象
	 * @param toFile 目标文件对象
	 * @return true/false
	 */
	public static boolean copyFile(File fromFile, File toFile) throws Exception {
		if (!isFile(fromFile) || toFile == null)
			return false;

		FileInputStream fis = new FileInputStream(fromFile);
		int len = fis.available();
		byte[] buf = new byte[len];
		for (int i = 0, b = fis.read(); b != -1; i++, b = fis.read()) {
			buf[i] = (byte) b;
		}
		fis.close();
		fis = null;

		FileOutputStream fos = new FileOutputStream(toFile);
		fos.write(buf);
		fos.flush();
		fos.close();
		fos = null;
		return true;
	}

	/**
	 * 文件拷贝类,输入路径
	 * 
	 * @param fromFile 源文件路径
	 * @param toFile 目标文件路径
	 * @return true/false
	 */
	public static boolean copyFile(String fromFile, String toFile) throws Exception {
		if (Validates.isEmptyBlank(fromFile) || Validates.isEmptyBlank(toFile))
			return false;

		File from = new File(fromFile.trim());
		File to = new File(toFile.trim());

		return copyFile(from, to);
	}

	/**
	 * 文件拷贝,输入源文件路径,目标目录,文件名
	 * 
	 * @param fromFile 源文件路径
	 * @param toDir 目标目录
	 * @param fileName 目录文件
	 * @return true/false
	 */
	public static boolean copyFile(String fromFile, String toDir, String fileName) throws Exception {
		if (Validates.isEmptyBlank(fromFile) || Validates.isEmptyBlank(toDir)
				|| Validates.isEmptyBlank(fileName))
			return false;

		File from = new File(fromFile.trim());
		if (!from.exists() || !from.isFile())
			return false;

		// 新建目录
		toDir = toDir.trim();
		if (!Validates.isEmpty(toDir)) {
			File dir = new File(toDir);
			if (!dir.exists())
				dir.mkdirs();

			dir = null;
		}

		if (toDir.lastIndexOf(Systems.getFileSeparator()) != toDir.length())
			toDir += Systems.getFileSeparator();

		File to = new File(toDir + fileName.trim());
		return copyFile(from, to);
	}

	/**
	 * 删除文件,如果路径为空或文件不存在则返回false
	 * 
	 * @param filePath 文件完整路径
	 * @return true/false 成功删除则返回true
	 */
	public static boolean deleteFile(String filePath) {
		if (Validates.isEmptyBlank(filePath))
			return false;

		File file = new File(filePath.trim());
		if (!file.exists())
			return false;

		return file.delete();
	}

	/**
	 * 删除文件夹
	 * 
	 * @param dir 文件夹路径
	 * @return true/false
	 */
	public static boolean deleteDirectory(String dir) throws Exception {
		if (Validates.isEmptyBlank(dir))
			return false;

		return deleteDirectory(new File(dir.trim()));
	}

	/**
	 * 删除文件夹
	 * 
	 * @param dir 文件夹路径
	 * @return true/false
	 */
	public static boolean deleteDirectory(File dir) throws Exception {
		if (dir == null || !dir.isDirectory())
			return false;

		File[] entries = dir.listFiles();
		for (File entry : entries) {
			if (entry.isFile()) {// 文件
				entry.delete();
			} else {// 目录递归删除
				deleteDirectory(entry);
			}
		}

		dir.delete();
		return true;
	}

	/**
	 * 删除文件夹
	 * 
	 * @param dir 文件夹路径
	 * @param forbidDirList 禁止删除的目录名称列表
	 * @return true/false
	 */
	public static boolean deleteDirectory(String dir, List<String> forbidDirList) throws Exception {
		if (Validates.isEmptyBlank(dir))
			return false;

		if (forbidDirList == null)
			return deleteDirectory(new File(dir.trim()));

		return deleteDirectory(new File(dir.trim()), forbidDirList);
	}

	/**
	 * 删除文件夹
	 * 
	 * @param dir 文件夹
	 * @param forbidDirList 禁止删除的目录名称列表
	 * @return true/false
	 */
	public static boolean deleteDirectory(File dir, List<String> forbidDirList) throws Exception {
		if (dir == null || !dir.isDirectory())
			return false;

		if (forbidDirList == null)
			return deleteDirectory(dir);

		boolean isAllowDeleteCurrentDir = true;
		File[] entries = dir.listFiles();
		for (File file : entries) {
			if (file.isFile()) {// 文件
				file.delete();
			} else {// 目录且不在禁止目录列表，递归删除
				boolean isAllowDelete = true;
				for (String forbid : forbidDirList) {
					if (Validates.isMatch(file.getName(), forbid)) {
						isAllowDelete = false;
						isAllowDeleteCurrentDir = false;
						break;
					}
				}

				if (isAllowDelete) {
					deleteDirectory(file, forbidDirList);
				}
			}
		}

		// 最后尝试删除目录，如果目录下没有禁止的则会成功，如果有禁止的是删不了则保留
		if (isAllowDeleteCurrentDir)
			dir.delete();

		return true;
	}

	/**
	 * 读取文件内容，并将内容以UTF-8字符串形式输出。 如果文件不存在，或路径错误，则返回NULL
	 * 
	 * @param filePath 文件路径
	 * @return 文件内容
	 */
	public static String readUTF8(String filePath) {
		byte[] bytes = read(filePath);
		return (bytes.length == 0) ? null : Strings.newStringUTF8(bytes);
	}

	/**
	 * 读取文件内容，并将内容以UTF-8字符串形式输出。 如果文件不存在，或路径错误，则返回NULL
	 * 
	 * @param file 文件对象
	 * @return 文件内容
	 */
	public static String readUTF8(File file) {
		byte[] bytes = read(file);
		return (bytes.length == 0) ? null : Strings.newStringUTF8(bytes);
	}

	/**
	 * 读取文件内容，并将内容以字符串形式输出。 如果文件不存在，或路径错误，则返回NULL
	 * 
	 * @param filePath 文件路径
	 * @param encoding 编码
	 * @return 文件内容
	 */
	public static String read(String filePath, String encoding) {
		byte[] bytes = read(filePath);
		return (bytes.length == 0) ? null : Strings.newString(bytes, encoding);
	}

	/**
	 * 读取文件内容，并将内容以字符串形式输出。 如果文件不存在，或路径错误，则返回NULL
	 * 
	 * @param file 文件对象
	 * @param encoding 编码
	 * @return 文件内容
	 */
	public static String read(File file, String encoding) {
		byte[] bytes = read(file);
		return (bytes.length == 0) ? null : Strings.newString(bytes, encoding);
	}

	/**
	 * 读取文件内容，并将内容以字符串形式输出。 如果文件不存在，或路径错误，则返回byte[0]
	 * 
	 * @param filePath 文件路径
	 * @return 文件内容
	 */
	public static byte[] read(String filePath) {
		if (!isFile(filePath))
			return new byte[0];

		FileInputStream fis = null;
		try {
			fis = new FileInputStream(filePath);
			return Streams.getBytes(fis, fis.available());
		} catch (IOException ex) {
			return new byte[0];
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
				}
				fis = null;
			}
		}
	}

	/**
	 * 读取文件内容，并将内容以字符串形式输出。 如果文件不存在，或路径错误，则返回byte[0]
	 * 
	 * @param file 文件对象
	 * @return 文件内容
	 */
	public static byte[] read(File file) {
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(file);
			return Streams.getBytes(fis, fis.available());
		} catch (IOException ex) {
			return new byte[0];
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
				}
				fis = null;
			}
		}
	}

	/**
	 * 读取文件内容，并将内容以字符串形式输出。 如果文件不存在，或路径错误，则返回NULL
	 * 
	 * @param filePath 文件路径
	 * @return 文件内容
	 */
	public static String readGZip(String filePath, String encoding) {
		byte[] bytes = read(filePath);
		if (bytes.length == 0)
			return null;

		return GZips.unGZipString(bytes, encoding);
	}

	/**
	 * 根据文件路径,名称,把内容以字节数组的方式写入到指定的文件中
	 * 
	 * @param filePath 文件路径
	 * @param is 文件流
	 * @return true/false 写入操作成功，返回true
	 */
	public static long writeReturnSize(String filePath, InputStream is) {
		if (Validates.isEmpty(filePath))
			return 0;

		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();

			int len = -1;
			byte[] bytes = new byte[1024];
			while ((len = is.read(bytes)) > 0) {
				bos.write(bytes, 0, len);
			}

			return writeReturnSize(filePath, bos.toByteArray());
		} catch (Exception e) {
			return 0;
		}
	}

	/**
	 * 根据文件路径，写入到指定的文件中
	 * 
	 * @param filePath 文件完整路径
	 * @param bytes 文件内容
	 * @return true/false 写入操作成功，返回true
	 */
	public static long writeReturnSize(String filePath, byte[] bytes) {
		if (Validates.isEmpty(filePath))
			return 0;

		// 获取文件所在目录,检查,如果不存在目录则创建
		String fileDirPath = getFileDirPath(filePath);
		File dirFile = new File(fileDirPath);
		if (!dirFile.exists())
			dirFile.mkdirs();

		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(filePath);
			fos.write(bytes);
			fos.flush();
			fos.close();
		} catch (Exception ex) {
			return 0;
		} finally {
			if (fos != null)
				try {
					fos.close();
				} catch (Exception e) {
				}
		}

		File file = new File(filePath);
		return file.length();
	}

	/**
	 * 根据文件路径,名称,把内容以字节数组的方式写入到指定的文件中
	 * 
	 * @param filePath 文件完整路径
	 * @param bytes 文件内容
	 * @return true/false 写入操作成功，返回true
	 */
	public static boolean write(String filePath, byte[] bytes) {
		if (Validates.isEmpty(filePath) || bytes == null)
			return false;

		// 获取文件所在目录,检查,如果不存在目录则创建
		String fileDirPath = getFileDirPath(filePath);
		File dirFile = new File(fileDirPath);
		if (!dirFile.exists())
			dirFile.mkdirs();

		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(filePath);
			fos.write(bytes);
			fos.flush();
			return true;
		} catch (IOException ex) {
			return false;
		} finally {
			if (fos != null)
				try {
					fos.close();
				} catch (Exception e) {
				}
		}
	}

	/**
	 * 根据文件路径,名称,把内容以流的方式写入到指定的文件中
	 * 
	 * @param filePath 文件完整路径
	 * @param content 文件内容
	 * @param encoding 编码
	 * @return true/false 写入操作成功，返回true
	 */
	public static boolean write(String filePath, String content, String encoding) {
		try {
			return write(filePath, content.getBytes(encoding));
		} catch (UnsupportedEncodingException e) {
			return false;
		}
	}

	/**
	 * 根据文件路径，指定UTF-8编码写入内容到文件
	 * 
	 * @param filePath 文件完整路径
	 * @param content 文件内容
	 * @return true/false 写入操作成功，返回true
	 */
	public static boolean writeUTF8(String filePath, String content) {
		return write(filePath, content, _UTF_8_);
	}

	/**
	 * 解压ZIP文件
	 * 
	 * @param zip ZIP文件
	 * @param toDir 解压目录
	 * @return　返回当前列表
	 * @throws IOException
	 */
	public static List<File> unzip(File zip, File toDir) throws IOException {
		List<File> files = new ArrayList<File>();
		ZipFile zf = new ZipFile(zip);
		Enumeration<?> entries = zf.entries();
		while (entries.hasMoreElements()) {
			ZipEntry entry = (ZipEntry) entries.nextElement();
			if (entry.isDirectory()) {
				new File(toDir, entry.getName()).mkdirs();
				continue;
			}

			InputStream input = null;
			OutputStream output = null;
			try {
				File f = new File(toDir, entry.getName());
				input = zf.getInputStream(entry);
				output = new FileOutputStream(f);
				Streams.putBytes(input, output);
				files.add(f);
			} finally {
				try {
					if (input != null)
						input.close();
				} catch (Exception e) {
				}
				;
				try {
					if (output != null)
						output.close();
				} catch (Exception e) {
				}
				;
			}
		}

		zf.close();
		return files;
	}

	/**
	 * 解压GZIP文件
	 * 
	 * @param gzip 解压文件
	 * @param toDir 解压目录
	 * @return 解压后的文件
	 * @throws IOException
	 */
	public static File ungzip(File gzip, File toDir) throws IOException {
		toDir.mkdirs();
		File out = new File(toDir, gzip.getName());
		GZIPInputStream input = null;
		FileOutputStream output = null;

		try {
			FileInputStream fin = new FileInputStream(gzip);
			input = new GZIPInputStream(fin);
			output = new FileOutputStream(out);
			Streams.putBytes(input, output);
		} finally {
			try {
				if (input != null)
					input.close();
			} catch (Exception e) {
			}
			;
			try {
				if (output != null)
					output.close();
			} catch (Exception e) {
			}
			;
		}

		return out;
	}

	/**
	 * 递归初始化文件列表
	 * 
	 * @param fileList 传入的文件列表引用，需先new，不允许为null;
	 * @param dir 指定搜索目录
	 * @param filter 过滤器
	 */
	public static void queryFilterList(List<File> fileList, File dir, Filter filter) {
		File[] list = dir.listFiles();
		for (int i = 0; i < list.length; i++) {
			File file = list[i];
			if (file.isFile()) {
				if (filter.access(file.getName()))
					fileList.add(file);
			} else {
				queryFilterList(fileList, file, filter);
			}
		}
	}

	/**
	 * 递归初始化文件列表
	 * 
	 * @param fileList 传入的文件列表引用，需先new，不允许为null;
	 * @param dir 指定搜索目录
	 * @param endsWith 后缀或以该结尾相同的数据,调用endsWith进行匹配，endsWith为null或空时表示全匹配
	 */
	public static void queryEndsWithList(List<File> fileList, File dir, String endsWith) {
		Filter filter = new FilterEndsWith().param(endsWith);
		queryFilterList(fileList, dir, filter);
	}

	/**
	 * 递归初始化文件列表
	 * 
	 * @param fileNameList 传入的文件列表引用，需先new，不允许为null;
	 * @param dir 指定搜索目录
	 * @param filter 过滤器
	 */
	public static void queryFilterNameList(List<String> fileNameList, File dir, Filter filter) {
		File[] list = dir.listFiles();
		for (int i = 0; i < list.length; i++) {
			File file = list[i];
			if (file.isFile()) {
				if (filter.access(file.getName()))
					fileNameList.add(file.getName());
			} else {
				queryFilterNameList(fileNameList, file, filter);
			}
		}
	}

	/**
	 * 递归初始化文件列表
	 * 
	 * @param fileNameList 传入的文件列表引用，需先new，不允许为null;
	 * @param dir 指定搜索目录
	 * @param endsWith 后缀或以该结尾相同的数据,调用endsWith进行匹配，endsWith为null或空时表示全匹配
	 */
	public static void queryEndsWithNameList(List<String> fileNameList, File dir, String endsWith) {
		Filter filter = new FilterEndsWith().param(endsWith);
		queryFilterNameList(fileNameList, dir, filter);
	}

	/**
	 * 读取目录的所有文件子目录名称列表
	 * 
	 * @param fileDir 目录路径
	 * @return 文件目录列表，需要判断是否为null，=null表示目录不存在或不是目录
	 */
	public static String[] getDirectoryList(String fileDir) {
		if (Validates.isEmptyBlank(fileDir))
			return null;

		File dir = new File(fileDir.trim());
		if (!dir.exists() || !dir.isDirectory())
			return null;

		String[] fileNames = dir.list();
		return fileNames;
	}

	/**
	 * 获取文件扩展名,则取得文件后缀 注:这里只是找"."
	 * 
	 * @param path 文件路径或文件名或URL路径
	 * @return 文件后缀,小写
	 */
	public static String getFileExt(String path) {
		if (Validates.isEmptyBlank(path))
			return "";

		path = path.trim();
		int pos = path.lastIndexOf(".");
		if (pos == -1)
			return "";

		String fileExt = path.substring(pos + 1);
		return fileExt.toLowerCase();
	}

	/**
	 * 增加文件路径的扩展名，如果有扩展名
	 * 
	 * @param fileExt 要新增的路径，为空返回原值，不为空+.+fileExt
	 * @return
	 */
	public static String fixFileExt(String fileExt) {
		return Validates.isEmptyBlank(fileExt) ? "" : "." + fileExt.trim();
	}

	/**
	 * 提取一个文件路径的目录结构， 如c:\\temp\\article.jsp，则返回c:\\temp\\。函数主要 用于提取路径的目录部份
	 * 
	 * @param filePath 文件完整路径
	 * @return 目录结构
	 */
	public static String getFileDirPath(String filePath) {
		String v = getFileDirPath(filePath, Systems.getFileSeparator());
		if (!Validates.isEmpty(v))
			return v;

		// 如果未找到，再尝试使用默认/方式获到
		return getFileDirPath(filePath, "/");
	}

	/**
	 * 提取一个文件路径的目录结构， 如c:\\temp\\article.jsp，则返回c:\\temp\\。函数主要 用于提取路径的目录部份
	 * 
	 * @param filePath 文件完整路径
	 * @param sep 指定分隔符
	 * @return 目录结构
	 */
	public static String getFileDirPath(String filePath, String sep) {
		int pos = filePath.lastIndexOf(sep);
		if (pos == -1)
			return "";

		return filePath.substring(0, pos);
	}

	/**
	 * 提取一个文件路径的文件名， 如c:\\temp\\article.jsp，则返回article.jsp。函数主要 用于提取路径的文件名称
	 * 
	 * @param filePath 文件完整路径
	 * @return 文件名称
	 */
	public static String getFileName(String filePath) {
		return getFileName(filePath, Systems.getFileSeparator());
	}

	/**
	 * 提取一个文件路径的文件名， 如c:\\temp\\article.jsp，则返回article.jsp。函数主要 用于提取路径的文件名称
	 * 
	 * @param filePath 文件完整路径
	 * @param sep 分隔符
	 * @return 文件名称
	 */
	public static String getFileName(String filePath, String sep) {
		int pos = filePath.lastIndexOf(sep);
		if (pos == -1)// 未找到，再使用/获取一次
			return getFileNameLinux(filePath);
		else
			return filePath.substring(pos + 1);
	}

	/**
	 * 提取一个文件路径的文件名， 如/opt/article.jsp，则返回article.jsp。函数主要 用于提取路径的文件名称
	 * 
	 * @param filePath 文件完整路径
	 * @return 文件名称
	 */
	public static String getFileNameLinux(String filePath) {
		int pos = filePath.lastIndexOf("/");
		if (pos == -1)
			return filePath;
		else
			return filePath.substring(pos + 1);
	}

	/**
	 * 通过类文件路径和类路径获取类名，异常返回null
	 * 
	 * @param classPath 类路径
	 * @param classFile 类文件路径
	 * @return 类名
	 */
	public static String getClassName(File classPath, File classFile) {
		try {
			String classPathDir = classPath.getCanonicalPath();
			String classFilePath = classFile.getCanonicalPath();

			return getClassName(classPathDir, classFilePath);
		} catch (IOException e) {
			return null;
		}
	}

	/**
	 * 通过类文件路径和类路径获取类名
	 * 
	 * @param classPath 类路径
	 * @param classFilePath 类文件路径
	 * @return 类名
	 */
	public static String getClassName(String classPath, String classFilePath) {// 格式如：d:\fadfox\bin\com\zhiqim\fadfox\bootstrap\Global.class
																				// 1.去除目录前缀,2.去除.class的后缀,3.把文件分隔符替换成.,4.把前面的.去掉
		String className = Strings.trimLeft(classFilePath, classPath);
		className = Strings.trimRight(className, ".class");
		className = Replaces.replaceAllEscape(className, Systems.getFileSeparator(), ".");
		className = Strings.trimLeft(className, ".");
		return className;
	}

	/**
	 * 生成文件目录路径，以当前年月日组成一个路径，结果如UNIX:2012/3/2,2012/11/24,WIN:2012\3\\2,2012\\11\\2
	 * 
	 * @return String 完整路径
	 */
	public static String getPathByCurrentDate() {
		Calendar date = Calendar.getInstance();
		int year = date.get(Calendar.YEAR);
		int month = date.get(Calendar.MONTH) + 1;
		int day = date.get(Calendar.DATE);

		return year + Systems.getFileSeparator() + month + Systems.getFileSeparator() + day;
	}

	/**
	 * 生成目录路径，以指定日期组成一个路径，结果如UNIX:2012/3/2,2012/11/24,WIN:2012\3\\2,2012\\11\\2
	 * 
	 * @return String 完整路径
	 */
	public static String getPathByCurrentDate(Date date) {
		Calendar calender = Calendar.getInstance();
		calender.setTime(date);

		int year = calender.get(Calendar.YEAR);
		int month = calender.get(Calendar.MONTH) + 1;
		int day = calender.get(Calendar.DATE);

		return year + Systems.getFileSeparator() + month + Systems.getFileSeparator() + day;
	}

	/**
	 * 删除多余的日志文件并重命名fileName,fileName.1,fileName.2,fileName.3成fileName.1,fileName.2,fileName.3,
	 * fileName.4
	 * 
	 * @param fileDir 文件目录
	 * @param fileName 文件名称
	 * @param fileMaxNum 文件最大个数
	 * @param renameCurFile 是否重命令当前文件成fileName.1
	 */
	public static void removeMaxFileAndRenameFile(String fileDir, String fileName, int fileMaxNum,
			boolean renameCurrentFile) {
		if (fileMaxNum <= 0)
			return;

		fileDir = toLinuxPath(fileDir);
		fileDir = Strings.removeEndsWith(fileDir, "/");

		// 把>=fileMaxNum文件名的都删除，<fileMaxNum的都改名后缀加1
		HashMap<Integer, File> renameMap = new HashMap<Integer, File>();

		File dir = new File(fileDir);
		for (File file : dir.listFiles()) {
			if (!file.isFile() || !file.getName().startsWith(fileName + "."))
				continue;

			String index = file.getName().substring(fileName.length() + 1);
			if (!Validates.isInteger(index))
				continue;

			int ind = Ints.toInt(index);
			if (ind >= fileMaxNum)
				file.delete();
			else
				renameMap.put(ind, file);
		}

		// 小于fileMaxNum的文件改名。从大到小重命名 .1,.2,.3成.2,.3,.4
		String filePath = fileDir + "/" + fileName;
		for (int i = fileMaxNum - 1; i >= 1; i--) {
			File file = renameMap.get(i);
			if (file == null)
				continue;

			file.renameTo(new File(filePath + "." + (i + 1)));
		}

		// 最后重命名当前文件为.1
		if (renameCurrentFile && Files.exists(filePath)) {
			new File(filePath).renameTo(new File(filePath + ".1"));
		}
	}
}